package ms.zuul.filter;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import ms.common.token.SessionKeyUtil;
import ms.common.util.string.StringUtil;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.util.StreamUtils;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.ROUTE_TYPE;

/**
 * Project Name: ms
 * File Name: MsRequestFilter
 * Package Name: ms.zuul.filter
 * Date: 2018/5/9  17:47
 * Copyright (c) 2018, tianyul All Rights Reserved.
 * 前台请求过滤器
 */
@Configuration
public class MsRequestFilter extends ZuulFilter {

    private static List<String> servicesNames;
    private static List<String> filterUrls;

    //放入允许过滤的服务
    static {
        //允许通过的url
        filterUrls = new ArrayList<>();
        filterUrls.add("/user/sign");
        filterUrls.add("/user/create");

        //过滤的服务
        servicesNames = new ArrayList<>();
        servicesNames.add("ms-mall");
    }

    private Logger logger = Logger.getLogger(MsManageRequestFilter.class);

    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 过滤器类型
     * pre 事前
     * routing 路由请求时候调用
     * error 发生错误时候调用
     * @return
     */
    @Override
    public String filterType() {
        return ROUTE_TYPE;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 是否过来
     * false 不过滤
     * true 过滤
     * @return
     */
    @Override
    public boolean shouldFilter() {
        RequestContext ctx = RequestContext.getCurrentContext();
        //过滤后台服务
        String serviceName = (String) ctx.get("serviceId");

        return servicesNames.contains(serviceName);
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest req = ctx.getRequest();
        logger.info("验证开始");
        logger.info(String.format("%s request to %s", req.getMethod(), req.getRequestURL().toString()));

        //过滤url
        String url = (String) ctx.get("requestURI");
        if(filterUrls.contains(url)) {
            return null;
        }

        //获取用户信息列表
        Map<String,Object> users = redisTemplate.opsForHash().entries("ms-mall");

        //校验登录信息
        if(SessionKeyUtil.isExpire(req) || StringUtil.isEmpty(users)) {
            //请求不下发，到此结束
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(200);
            ctx.getResponse().setCharacterEncoding("utf-8");
            ctx.setResponseBody(JSON.toJSONString(new MsResponseBody(ResponseCode.TOKEN_OVERDUE)));
            return null;
        }
        //获取openid
        String openid = SessionKeyUtil.getOpenid(req);

        InputStream in = (InputStream) ctx.get("requestEntity");
        if (in == null) {
            try {
                in = ctx.getRequest().getInputStream();
                String body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));
                Map<String, Object> map = JSONObject.parseObject(body, Map.class);
                map.put("openid", openid);
                body = JSONObject.toJSONString(map);
                final byte[] reqBodyBytes = body.getBytes();
                ctx.setRequest(new HttpServletRequestWrapper(ctx.getCurrentContext().getRequest()) {
                    @Override
                    public ServletInputStream getInputStream() {
                        return new ServletInputStreamWrapper(reqBodyBytes);
                    }

                    @Override
                    public int getContentLength() {
                        return reqBodyBytes.length;
                    }

                    @Override
                    public long getContentLengthLong() {
                        return reqBodyBytes.length;
                    }
                });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        logger.info("验证成功");
        return null;
    }

}
